/*==========================================================================   
 *                                                                                                                  
 * Copyright (c) 2012 Nodecom Corporation.  All Rights Reserved.                     
 *                                                                                                               
 *----------------------------------------------------------------------------------------
 *
 * PROJECT             ANDROID 2.3
 *
 * LANGUAGE          ANSI C
 *
 * SUBSYSTEM        DIAGGRAB
 *
 * DESCRIPTION     
 *                       
 *
 *---------------------------------------------------------------------------------------
 *
 * HOSTORY
 * 
 *       when            who               what, where, why     
 *
 * 2013/09/15           caogang           initial version.
 *
 *========================================================================*/

/*-------------------------------------------------------------------------------------*/
/*        INCLUDE FILE                                                                 */
/*-------------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include "stdarg.h"
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <sched.h> 
#include <time.h>
#include <termios.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <unistd.h>
#include <pthread.h>

/*-------------------------------------------------------------------------------------*/
/*        MACRO DEFINITION                                                             */
/*-------------------------------------------------------------------------------------*/
#define PORT_NAME_PREFIX        "/dev/ttyUSB"
#define LOG_FILE_NAME           "diaggrab_log.txt"

#define  MAX_PATH       1024

#define QUALCOMM_QXDM_LOG_REQ_FLAG                      "pkt req"
#define QUALCOMM_QXDM_LOG_RSP_FLAG                      "pkt rsp"
#define QUALCOMM_QXDM_LOG_END_FLAG                      "pkt end"
#define QUALCOMM_QXDM_LOG_LINE_SIZE                     (512 * 1024)
#define QUALCOMM_QXDM_LOG_PKG_SIZE                      (512 * 1024)
#define QUALCOMM_QXDM_LOG_CONFIGFILE_SIZE               (512 * 1024)
#define QUALCOMM_QXDM_LOG_BUFFER_SIZE                   (1 * 1024 * 1024)
#define QUALCOMM_QXDM_LOG_FILE_SIZE                     (50 * 1024 * 1024)
#define QUALCOMM_QXDM_LOG_WRITE_MIN                     (64 * 1024)
/*-------------------------------------------------------------------------------------*/
/*        TYPE DEFINITION                                                              */
/*-------------------------------------------------------------------------------------*/

/*-------------------------------------------------------------------------------------*/
/*        GLOBAL VARIABLE DEFINITION                                                   */
/*-------------------------------------------------------------------------------------*/

/*-------------------------------------------------------------------------------------*/
/*        LOCAL VARIABLE DEFINITION                                                    */
/*-------------------------------------------------------------------------------------*/
int g_fd_port = -1;
int g_is_serial_connect = 0;
int g_is_qxdm_logging = 0;
pthread_t g_tid_log;    
char g_str_qualcomm_log_dir[MAX_PATH];
char g_str_qualcomm_log_file[MAX_PATH] = LOG_FILE_NAME;

pthread_t g_tid_logtest;    

/*-------------------------------------------------------------------------------------*/
/*        LOCAL FUNCTION DEFINITION                                                    */
/*-------------------------------------------------------------------------------------*/
void log_file(const char *str_file_name, const char * str_fmt,...)
{
        FILE *fp;

        fp = fopen(str_file_name, "a+t");
        if(fp)
        {
                static char log_trace[256];
                va_list ap;
                struct tm *tm;
                time_t t;

                va_start(ap, str_fmt);
                vsnprintf(log_trace, sizeof(log_trace), str_fmt, ap);
                va_end(ap);

                t = time(NULL);
                tm = localtime(&t);
                fprintf(fp, "[%02d/%02d/%02d/ %02d:%02d:%02d]: %s\n", 
                                tm->tm_year, 
                                tm->tm_mon, 
                                tm->tm_mday, 
                                tm->tm_hour, 
                                tm->tm_min, 
                                tm->tm_sec,
                                log_trace);
                fclose(fp);
        }
}

void log_message(const char * str_fmt,...)
{
        static char log_trace[256];
        va_list ap;

        va_start(ap, str_fmt);
        vsnprintf(log_trace, sizeof(log_trace), str_fmt, ap);
        va_end(ap);


        printf("DIAGGRAB: %s\r\n", log_trace);
}

void log_message_nr(const char * str_fmt,...)
{
        static char log_trace[256];
        va_list ap;

        va_start(ap, str_fmt);
        vsnprintf(log_trace, sizeof(log_trace), str_fmt, ap);
        va_end(ap);

        printf("%s", log_trace);
}

void sleepms(long msec)
{
#if 0
        struct timespec ts;
        int err;

        ts.tv_sec = (msec / 1000);
        ts.tv_nsec = (msec % 1000) * 1000 * 1000;

        do 
        {
                err = nanosleep (&ts, &ts);
        } while (err < 0 && errno == EINTR);
#else
        long long us = msec;
        us *= 1000;
        usleep(us);
#endif
}

int serial_connect(const char *str_port)
{
        int trycnt = 0;
        struct termios newtio;

        if(!str_port)
        {
                log_message("invalid parameter!");
                return -1;
        }

        if(g_is_serial_connect == 1) 
        {
                log_message("port[%s] opened already!", str_port);
                return 1;
        }

        log_message("port[%s] connecting...", str_port);

        g_fd_port = open (str_port, O_RDWR);
        if(g_fd_port < 0) 
        {
                log_message("port[%s] open failed! errno[%d]", str_port, errno);
                goto error_exit;
        }

        if(tcgetattr(g_fd_port, &newtio) != 0)
        {
                log_message("port[%s] tcgetattr failed! errno[%d]", str_port, errno);
                goto error_exit;
        }

        cfmakeraw(&newtio);

        /*set baudrate*/
        cfsetispeed(&newtio, B4000000);
        cfsetospeed(&newtio, B4000000);

        /*set char bit size*/
        newtio.c_cflag &= ~CSIZE;
        newtio.c_cflag |= CS8;

        /*set check sum*/
        newtio.c_cflag &= ~PARENB;

        /*set stop bit*/
        newtio.c_cflag &= ~CSTOPB;
        newtio.c_cflag |= CLOCAL |CREAD;
        newtio.c_cflag &= ~(PARENB | PARODD);

        newtio.c_iflag &= ~(INPCK | BRKINT |PARMRK | ISTRIP | INLCR | IGNCR | ICRNL);
        newtio.c_iflag |= IGNBRK;
        newtio.c_iflag &= ~(IXON|IXOFF|IXANY);

        newtio.c_oflag = 0;

        newtio.c_lflag = 0;

        /*set wait time*/
        newtio.c_cc[VMIN] = 0;
        newtio.c_cc[VTIME] = 0;

        tcflush(g_fd_port, TCIFLUSH);
        tcflush(g_fd_port, TCOFLUSH);

        if(tcsetattr(g_fd_port, TCSANOW, &newtio) !=0 )
        {
                log_message("port[%s] tcsetattr failed! errno[%d]", str_port, errno);
                goto error_exit;
        }

        g_is_serial_connect = 1;

        log_message("port[%s] connected!", str_port);

        return 0;

error_exit:

        if(g_fd_port >= 0)
        {
                close(g_fd_port);
                g_fd_port = -1;
        }

        return -1;
}

int serial_autoconnect()
{
        char str_port_name[MAX_PATH];
        char str_cmd_line[MAX_PATH];
        char str_cmd_rsp_line[MAX_PATH];
        int port_index;    
        int ret_val;
        int fd;

        if(g_is_serial_connect == 1) 
        {
                log_message("serial opened already!");
                return 1;
        }

        memset(str_port_name, 0, sizeof(str_port_name));
        for(port_index = 0; port_index < 50; port_index++)
        {
                sprintf(str_port_name, "%s%d", PORT_NAME_PREFIX, port_index);
                if(access(str_port_name, F_OK) == 0)
                {
                        log_message("port[%s] found!", str_port_name);
                        break;
                }
                else
                {
                        log_message("port[%s] try error! errno[%d]", str_port_name, errno);
                }
        }

        if(access(str_port_name, F_OK) != 0)
        {
                log_message("no port found! errno[%d]", errno);
                goto error_exit;
        }

        ret_val = chmod(str_port_name, S_IRWXU | S_IRWXG | S_IRWXO);
        if(ret_val < 0)
        {
                log_message("failed to change <%s> mode! ret_val: %d", str_port_name, ret_val);
        }
        else
                log_message("change <%s> mode ok! ret_val: %d", str_port_name, ret_val);

        if(serial_connect(str_port_name) < 0)
        {
                log_message("failed to open serial port <%s> !", str_port_name);
                goto error_exit;
        }

        return 0;

error_exit:
        return -1;
}

int serial_disconnect()
{
        if(g_fd_port >= 0)
        {
                close(g_fd_port);
                g_fd_port = -1;
        }

        g_is_serial_connect = 0;

        return 0;
}

int serial_flush()
{
        if(g_fd_port >= 0)
        {
                tcflush(g_fd_port, TCIFLUSH);
                tcflush(g_fd_port, TCOFLUSH);
        }

        return 0;
}

unsigned long serial_write(unsigned char *p_out_buffer, unsigned long out_buffer_size)
{
        unsigned long cb_wrote = 0;

        if(g_fd_port < 0)
        {
                log_message("please open port first!");    
                return 0;
        }

        if(out_buffer_size <= 0)
                return 0;

        /*just write data to device*/
        cb_wrote = write(g_fd_port, p_out_buffer, out_buffer_size);
        if(cb_wrote <= 0)   
        {
                log_message("port[0x%x] write error! errno[%d]", g_fd_port, errno);
                return 0;
        }

        return cb_wrote;
}

unsigned long serial_write_hexstring(const char *str_in_buffer)
{
        unsigned long write_cnt = 0;
        unsigned long str_len = 0;
        char ch_high, ch_low;
        unsigned char *buffer_to_write = NULL; 
        unsigned long cb_wrote = 0;

        if(g_fd_port < 0)
        {
                log_message("please open port first!");    
                return 0;
        }

        str_len = (unsigned long)strlen(str_in_buffer);

        if(!str_in_buffer || str_len <= 0)
                goto error_exit;

        buffer_to_write = (unsigned char *)malloc(str_len);
        if(!buffer_to_write)
        {
                log_message("malloc %d bytes failed! errno[%d]", str_len, errno);    
                goto error_exit;
        }

        while(*str_in_buffer != '\0' && (*str_in_buffer + 1) != '\0')
        {
                ch_high = tolower(*str_in_buffer);
                ch_low = tolower(*(str_in_buffer + 1));
                if ((('0' <= ch_high && '9' >= ch_high) || ('a' <= ch_high && 'f' >= ch_high)) && 
                                (('0' <= ch_low && '9' >= ch_low) || ('a' <= ch_low && 'f' >= ch_low)))
                {
                        if ('0' <= ch_high && '9' >= ch_high)
                        {
                                buffer_to_write[write_cnt] = (ch_high - '0') << 4;
                        }
                        else
                        {
                                buffer_to_write[write_cnt] = (0x0a + ch_high - 'a') << 4;
                        }

                        if ('0' <= ch_low && '9' >= ch_low)
                        {
                                buffer_to_write[write_cnt] |= (ch_low - '0');
                        }
                        else
                        {
                                buffer_to_write[write_cnt] |= (0x0a + ch_low - 'a');
                        }
                        write_cnt++;
                        str_in_buffer += 2;
                }
                else
                        str_in_buffer++;
        }

        if(write_cnt <= 0)
                goto error_exit;

        /*just write data to device*/
        cb_wrote = write(g_fd_port, buffer_to_write, write_cnt);
        if(cb_wrote <= 0)   
        {
                log_message("port[0x%x] write error! errno[%d]", g_fd_port, errno);
                goto error_exit;
        }

        if(buffer_to_write)
                free(buffer_to_write);

        return cb_wrote;

error_exit:

        if(buffer_to_write)
                free(buffer_to_write);

        return 0;    
}

unsigned long serial_read(unsigned char *p_in_buffer, unsigned long in_buffer_size, unsigned long *p_bytes_read)
{
        int read_len = 0;

        if(g_fd_port < 0)
        {
                log_message("please open port first!");    
                return 0;
        }

        if(!p_in_buffer || in_buffer_size <= 0)
                return 0;

        read_len = read(g_fd_port, p_in_buffer, in_buffer_size);
        if(read_len < 0)
        {
                log_message("read com port error :%d,  errno[%d]", read_len, errno);
                read_len = 0;
        }

        if(p_bytes_read)
                *p_bytes_read = read_len;

        return read_len;
}

void *qualcomm_serial_log_test_thread(void *arg)
{
#define MAX_TEST_TIMES       3000
#define MAX_TEST_COUNT      1
#define MAX_READ_BUFFER     2048
#define MAX_READ_TRY      100
        int testidx = 0;
        int read_rsp_idx = 0;
        int read_rsp_try = 0;
        int fd;
        struct termios ios;
        size_t retlen;
        size_t cur;
        size_t len;
        ssize_t written;
        int cur_index = 0;
        char *p_read_buffer;
        const char *str_cur_at;
        const char *str_at_tab[MAX_TEST_COUNT] = 
        {
                "at+creg?"
        };

        if(chmod(PORT_NAME_PREFIX "2", S_IRWXU | S_IRWXG | S_IRWXO) < 0)
        {
                log_message("failed to change <%s> mode! errno: %d", PORT_NAME_PREFIX "2", errno);
        }

        fd = open(PORT_NAME_PREFIX "2", O_RDWR);
        if(fd < 0)
        {
                log_message("failed to open log test port. errno[%d]", errno);
                return NULL;
        }

        tcgetattr(fd, &ios);
        ios.c_lflag = 0;    /* disable ECHO, ICANON, etc... */
        ios.c_cc[VMIN] = 0;
        ios.c_cc[VTIME] = 0;
        tcsetattr(fd, TCSANOW, &ios);

        tcflush(fd, TCIFLUSH);
        tcflush(fd, TCOFLUSH);

        p_read_buffer = (char *)malloc(MAX_READ_BUFFER);
        if(!p_read_buffer)
        {
                log_message("malloc (%d) bytes buffer for read at command response failed! errno[%d]", MAX_READ_BUFFER, errno);
                goto error_exit;
        }

        sleepms(1000);

        log_message("test started!");

        cur_index = 0;
        while(g_is_qxdm_logging && testidx++ < MAX_TEST_TIMES)
        {
                str_cur_at = str_at_tab[cur_index];
                len = strlen(str_cur_at);
                cur = 0;
                while (cur < len) 
                {
                        do 
                        {
                                written = write (fd, str_cur_at + cur, len - cur);
                        } while (written < 0 && errno == EINTR);

                        if (written < 0) 
                        {
                                log_message("failed to send at command <%s>!  errno[%d]", str_cur_at, errno);
                                sleepms(1000);
                                continue;
                        }

                        cur += written;
                }

                /* the \r  */
                do 
                {
                        written = write (fd, "\r" , 1);
                } while ((written < 0 && errno == EINTR) || (written == 0));

                if (written < 0) 
                {
                        log_message("failed to send at command <%s>! errno[%d]", str_cur_at, errno);
                        sleepms(1000);
                        continue;
                }

                read_rsp_idx = 0;
                read_rsp_try = MAX_READ_TRY;
                do
                {
                        sleepms(10);
                        retlen = read(fd, p_read_buffer + read_rsp_idx, MAX_READ_BUFFER - read_rsp_idx);
                        read_rsp_idx += retlen;
                        if(strstr(p_read_buffer, "OK") != NULL)
                        {
                                break;
                        }
                }while(--read_rsp_try > 0);

                if(read_rsp_try == 0)
                {
                        log_message("failed to get response of at command <%s>, recved<%s>!", str_cur_at,  p_read_buffer);
                }

                cur_index++;
                if(cur_index >= MAX_TEST_COUNT)
                        cur_index = 0;
        }

error_exit:

        close(fd);

        if(p_read_buffer)
                free(p_read_buffer);

        log_message("test stopped!");

        return NULL;
}

int qualcomm_serial_log_teststart()
{
        int ret;
        pthread_attr_t attr;
        struct sched_param param;     

        log_message("qualcomm_serial_log_teststart called");

        pthread_attr_init (&attr);
        pthread_attr_getschedparam(&attr, &param);  
        param.sched_priority=80;  
        pthread_attr_setschedparam(&attr, &param);  
        pthread_attr_setschedpolicy(&attr, SCHED_RR);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
        ret = pthread_create(&g_tid_logtest, &attr, qualcomm_serial_log_test_thread, &attr);
        if (ret < 0)
        {
                log_message("pthread_create log test thread create failed! errno[%d]", errno);
                goto error_exit;
        }

error_exit:

        pthread_attr_destroy(&attr);

        return 0;
}

void *qualcomm_serial_log_thread(void *arg)
{
        unsigned char *rx_buffer;
        int cur_pos;
        int file_size;
        int recved_bytes;
        int retlen;
        FILE *h_logfile = NULL;

        rx_buffer = (unsigned char *)malloc(QUALCOMM_QXDM_LOG_BUFFER_SIZE);
        if(!rx_buffer)
        {
                log_message("malloc %d bytes error, errno(%d)!", QUALCOMM_QXDM_LOG_BUFFER_SIZE, errno);
                return NULL;
        }

        log_file(g_str_qualcomm_log_file, "log started!");

        recved_bytes = 0;
        while(g_is_qxdm_logging)
        {
                if(h_logfile)
                {
                        /* close the file */
                        cur_pos = ftell(h_logfile);
                        fseek(h_logfile, 0, SEEK_END);
                        file_size = ftell(h_logfile);
                        fseek(h_logfile, cur_pos, SEEK_SET);
                        if(file_size > QUALCOMM_QXDM_LOG_FILE_SIZE)
                        {
                                fflush(h_logfile);
                                fclose(h_logfile);
                                h_logfile = NULL;
                        }
                }

                if(!h_logfile)
                {
                        struct statfs disk_info;
                        struct tm *tm;
                        time_t t;
                        char str_logfile[MAX_PATH] = {0};
                        int i;

#if 0
                        /* get disk spaces */
                        if(statfs(g_str_qualcomm_log_dir, &disk_info) >= 0)
                        {
                                /*
                                   log_message("statfs[%d, %d, %d, %d, %d, %d, %d, %d]!", 
                                   disk_info.f_type, 
                                   disk_info.f_bsize,
                                   disk_info.f_blocks,
                                   disk_info.f_bfree,
                                   disk_info.f_bavail,
                                   disk_info.f_files,
                                   disk_info.f_ffree,
                                   disk_info.f_frsize);
                                 */
                                unsigned long long total_size = disk_info.f_frsize * disk_info.f_bsize;
                                if(total_size  < 3 * QUALCOMM_QXDM_LOG_FILE_SIZE && total_size > 0)
                                {
                                        log_message("[%s, 0x%x] no space! total_size: %d bytes!", g_str_qualcomm_log_dir, disk_info.f_type, disk_info.f_type, total_size);
                                        break;
                                }
                        }
#endif

                        /* create log file */
                        t = time(NULL);
                        tm = localtime(&t);
                        sprintf(str_logfile, "%s%02d%02d%02d%02d%02d%02d.qmdl", 
                                        g_str_qualcomm_log_dir,
                                        tm->tm_year, 
                                        tm->tm_mon, 
                                        tm->tm_mday, 
                                        tm->tm_hour, 
                                        tm->tm_min, 
                                        tm->tm_sec);

                        log_file(g_str_qualcomm_log_file, "log file: %s", str_logfile);

                        h_logfile = fopen(str_logfile, "wb");
                        if(!h_logfile)
                        {
                                log_message("create log file failed, errno(%d).", errno);
                                break;
                        }

                        log_message("log file(%s)", str_logfile);
                }

                /* read log to file */
                retlen = serial_read(rx_buffer + recved_bytes, QUALCOMM_QXDM_LOG_BUFFER_SIZE - recved_bytes, NULL);
                recved_bytes += retlen;
                if(recved_bytes >= QUALCOMM_QXDM_LOG_WRITE_MIN)
                {
                        fwrite(rx_buffer, recved_bytes, 1, h_logfile);
                        recved_bytes = 0;
                }

                /* print current status */
                {
                        static unsigned long start_tick = 0;
                        static unsigned long cur_tick = 0;
                        static unsigned long reced_bytes = 0;
                        unsigned long periodtick = 0;

                        reced_bytes += retlen;
                        if(start_tick == 0)
                                start_tick = time(NULL);
                        else
                        {
                                cur_tick = time(NULL);
                                periodtick = cur_tick - start_tick;
                                if(periodtick >= 3)
                                {
                                        log_message("recved_bytes(%u) recvd(%u), tick(%u), %uB/S",recved_bytes, reced_bytes, periodtick, reced_bytes / periodtick);             
                                        start_tick = cur_tick;
                                        reced_bytes = 0;
                                }
                        }

                }
        }

        if(h_logfile)
        {
                fflush(h_logfile);
                fclose(h_logfile);
        }

        if(rx_buffer)
                free(rx_buffer);

        serial_disconnect();    

        log_file(g_str_qualcomm_log_file, "log stopped!");

        return NULL;
}

int qualcomm_serial_logstart(const char *str_config_file, const char *str_log_dir)
{
        int ret;
        pthread_attr_t attr;
        struct sched_param param;     
        FILE *h_config_file = NULL;
        int config_file_size;
        char *p_config_file_buffer = NULL;
        char *p_config_req = NULL;
        char *p_config_req_line = NULL;
        unsigned char *p_config_rsp_line = NULL;
        unsigned char ch, stmp[4]="";
        int b_req, b_rsp, b_rsp_ok;
        int pos, line_pos, rsp_len, try_read;
        int i;

        g_is_qxdm_logging = 1;

        if(serial_autoconnect() <0)
        {
                goto error_exit;
        }

        /* 1: flush serial buffer. */
        serial_flush();

        /* 2: read config file and write to serial. */
        h_config_file = fopen(str_config_file, "r");
        if(!h_config_file)
        {
                log_message("read configuration file <%s> failed, errno(%d)!", str_config_file, errno);
                goto error_exit;
        }

        /* get file size */
        fseek(h_config_file, 0, SEEK_END);
        config_file_size = ftell(h_config_file);
        fseek(h_config_file, 0, SEEK_SET);
        if(config_file_size <= 0)
        {
                log_message("get configuration file size failed, size(%d)!", config_file_size);
                goto error_exit;
        }

        /* malloc buffer for writting configuration file */
        p_config_file_buffer = (char *)malloc(config_file_size);
        if(!p_config_file_buffer)
        {
                log_message("malloc (%d) bytes buffer for configuration file failed! errno[%d]", config_file_size, errno);
                goto error_exit;
        }

        p_config_req = (char *)malloc(QUALCOMM_QXDM_LOG_PKG_SIZE);
        if(!p_config_req)
        {
                log_message("malloc (%d) bytes buffer for requst package failed! errno[%d]", QUALCOMM_QXDM_LOG_PKG_SIZE, errno);
                goto error_exit;
        }

        p_config_req_line = (char *)malloc(QUALCOMM_QXDM_LOG_LINE_SIZE);
        if(!p_config_req_line)
        {
                log_message("malloc (%d) bytes buffer for requst package line failed! errno[%d]", QUALCOMM_QXDM_LOG_LINE_SIZE, errno);
                goto error_exit;
        }

        p_config_rsp_line = (unsigned char *)malloc(QUALCOMM_QXDM_LOG_LINE_SIZE);
        if(!p_config_rsp_line)
        {
                log_message("malloc (%d) bytes buffer for response package line failed! errno[%d]", QUALCOMM_QXDM_LOG_LINE_SIZE, errno);
                goto error_exit;
        }

        config_file_size = fread(p_config_file_buffer, 1, config_file_size, h_config_file);
        if(config_file_size <= 0)
        {
                log_message("read configuration file failed, errno(%d)!", errno);
                goto error_exit;
        }

        log_message("++++++++++++++++++++++++++++++++++++++++++");
        log_message("config file <%s>, size<%d>", str_config_file, config_file_size);

        pos = 0;
        line_pos = 0;
        b_req = 0;
        b_rsp = 0;

        short sch = *(short *)p_config_file_buffer;
        while(0x2d2d == sch &&
                        (pos < config_file_size && line_pos < QUALCOMM_QXDM_LOG_LINE_SIZE))
        {
                ch = (unsigned char)p_config_file_buffer[pos++];
                if(ch == '\r')
                {
                        continue;
                }           
                else if(ch == '\n' || pos == config_file_size)
                {
                        if(pos == config_file_size)
                                p_config_req_line[line_pos++] = ch;

                        p_config_req_line[line_pos] = '\0';

                        if(strstr(p_config_req_line, QUALCOMM_QXDM_LOG_REQ_FLAG))
                        {
                                // log_message("-----------------------pkt req--------------------------");
                                b_rsp = 0;
                                b_req = 1;
                                memset(p_config_req, 0, sizeof(p_config_req));
                        }
                        else if(strstr(p_config_req_line, QUALCOMM_QXDM_LOG_RSP_FLAG))
                        {
                                if(strlen(p_config_req) > 0 && serial_write_hexstring(p_config_req) > 0)
                                {
                                        // log_message("-----------------------pkt rsp--------------------------");
                                        b_rsp_ok = 0;
                                        try_read = 500;
                                        do
                                        {
                                                // log_message_nr("DIAGGRAB: ");
                                                rsp_len = serial_read(p_config_rsp_line, QUALCOMM_QXDM_LOG_PKG_SIZE, NULL);
                                                if(rsp_len >= 0)
                                                {
                                                        for(i = 0; i < rsp_len; i++)
                                                        {
                                                                // log_message_nr("%02x ", p_config_rsp_line[i]);
                                                                if(p_config_rsp_line[i] == 0x7e)
                                                                        b_rsp_ok = 1;
                                                        }
                                                        // log_message_nr("\r\n");
                                                }
                                                else
                                                {
                                                        sleepms(1);
                                                }
                                        }while(!b_rsp_ok && try_read--);
                                }
                                // log_message("-----------------------pkt rsp std--------------------------");
                                b_rsp = 1;
                                b_req = 0;
                        }
                        else if(strstr(p_config_req_line, QUALCOMM_QXDM_LOG_END_FLAG))
                        {
                                // log_message("-----------------------pkt end--------------------------");              
                                b_rsp = 0;
                                b_req = 0;                   
                        }
                        else if(b_req)
                        {
                                strcat(p_config_req, p_config_req_line);
                        }
                        else if(b_rsp)
                        {
                                //log_message("%s", p_config_req_line);        
                        }
                        //else
                        //    log_message("-----------------------pkt error!--------------------------");               

                        line_pos = 0;
                        continue;
                }
                p_config_req_line[line_pos++] = ch;
        }

        while(0x2d2d != sch && 
                        (pos < config_file_size && line_pos < QUALCOMM_QXDM_LOG_LINE_SIZE))
        {
                ch = p_config_file_buffer[pos++];
                sprintf(stmp, "%02X ", ch);
                memcpy(&p_config_req_line[(line_pos++)*3], stmp, 3);
                if(0x7e == ch){
                        p_config_req_line[pos*3+3] = '\0';
                        if(line_pos > 3 && serial_write_hexstring(p_config_req_line) > 0)
                        {
                                b_rsp_ok = 0;
                                try_read = 500;
                                do
                                {
                                        rsp_len = serial_read(p_config_rsp_line,
                                                        QUALCOMM_QXDM_LOG_PKG_SIZE, NULL);
                                        if(rsp_len >= 0)
                                        {
                                                for(i = 0; i < rsp_len; i++)
                                                {
                                                        if(p_config_rsp_line[i] == 0x7e)
                                                                b_rsp_ok = 1;
                                                }
                                        }
                                        else
                                        {
                                                sleepms(1);
                                        }
                                }while(!b_rsp_ok && try_read--);
                        }
                        memset(p_config_req_line, '\0', line_pos + 1);
                        line_pos = 0;
                }
        } 

        log_message("------------------------------------------");
        // 3: create thread to log file.
        {
                struct tm *tm;
                time_t t;
                char str_dir[MAX_PATH];
                int i, len;

                strcpy(str_dir, str_log_dir);
                len = strlen(str_dir);
                if(str_dir[len - 1] == '\\' || str_dir[len - 1] == '/')
                {
                        str_dir[len - 1] = '\0';
                }

                t = time(NULL);
                tm = localtime(&t);
                sprintf(g_str_qualcomm_log_dir, "%s/qxdmlog_%02d%02d%02d%02d%02d%02d/", 
                                str_log_dir,
                                tm->tm_year, 
                                tm->tm_mon, 
                                tm->tm_mday, 
                                tm->tm_hour, 
                                tm->tm_min, 
                                tm->tm_sec);

                strcpy(g_str_qualcomm_log_file, str_log_dir);
                strcat(g_str_qualcomm_log_file, "/");
                strcat(g_str_qualcomm_log_file, LOG_FILE_NAME);

                for (i = 1; i < MAX_PATH && g_str_qualcomm_log_dir[i] != 0; i++)
                {
                        if (g_str_qualcomm_log_dir[i] == '\\'  || g_str_qualcomm_log_dir[i] == '/' )
                        {
                                strcpy(str_dir, g_str_qualcomm_log_dir);
                                str_dir[i] = '\0';
                                mkdir(str_dir, 0700);
                        }
                }

                log_message("Log startted, config<%s>, log dir<%s>", str_config_file, g_str_qualcomm_log_dir);
        }

        pthread_attr_init (&attr);
        pthread_attr_getschedparam(&attr, &param);  
        param.sched_priority=99;  
        pthread_attr_setschedparam(&attr, &param);  
        pthread_attr_setschedpolicy(&attr, SCHED_RR);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
        ret = pthread_create(&g_tid_log, &attr, qualcomm_serial_log_thread, &attr);
        if (ret < 0)
        {
                log_message("pthread_create log thread create failed.  errno[%d]", errno);
                goto error_exit;
        }
        pthread_attr_destroy(&attr);

        return 0;

error_exit:

        log_message("Log start error.");

        serial_disconnect();

        if(h_config_file)
                fclose(h_config_file);

        if(p_config_file_buffer)
                free(p_config_file_buffer);
        if(p_config_req)
                free(p_config_req);
        if(p_config_req_line)
                free(p_config_req_line);
        if(p_config_rsp_line)
                free(p_config_rsp_line);

        return -1;    
}

int qualcomm_serial_logstop()
{
        if(serial_autoconnect() <0)
        {
                goto error_exit;
        }

        if(g_is_qxdm_logging == 1)
        {
                if(!serial_write_hexstring("60 00 12 6a  7e")) 
                        goto error_exit;
                sleepms(100);
                if(!serial_write_hexstring("73 00 00 00  00 00 00 00    da 81 7e")) 
                        goto error_exit;
                sleepms(100);
                if(!serial_write_hexstring("7d 5d 05 00  00 00 00 00    00 74 41 7e")) 
                        goto error_exit;
                sleepms(100);
                if(!serial_write_hexstring("4b 04 0e 00  0d d3 7e")) 
                        goto error_exit;
                sleepms(100);
                if(!serial_write_hexstring("4b 04 0e 00  0d d3 7e")) 
                        goto error_exit;
                sleepms(100);

                g_is_qxdm_logging = 0;

                log_message("Log stopped, dir<%s>.", g_str_qualcomm_log_dir);
        }

        serial_disconnect();  

        return 1;

error_exit:

        log_message("Log stop error.");

        serial_disconnect();  

        return 0;   
}

static void usage(const char *argv0)
{
        log_message("Usage: %s -c <log config file> -[start/stop]", argv0);
        exit(-1);
}

int main(int argc, char **argv)
{
        const char * configFilePath = NULL;
        unsigned char runmode = 0;  // 0: start, 1: stop, 2: test mode start
        int i;

        for (i = 1; i < argc ;) 
        {
                if (0 == strcmp(argv[i], "-c") && (argc - i > 1)) 
                {
                        configFilePath = argv[i + 1];
                        i += 2;
                } 
                else if(0 == strcmp(argv[i], "-start")) 
                {
                        i++;
                        runmode = 0;
                }
                else if(0 == strcmp(argv[i], "-stop")) 
                {
                        i++;
                        runmode = 1;
                } 
                else if(0 == strcmp(argv[i], "-test")) 
                {
                        i++;
                        runmode = 2;
                }         
                else 
                {
                        usage(argv[0]);
                        break;
                }
        }

        if (configFilePath == NULL) 
        {
                usage(argv[0]);
                goto error_exit;
        }

        log_message("run mode %d", runmode);
        if(runmode == 0 || runmode == 2)
        {
                log_message("configuration file(%s)", configFilePath);
                if(qualcomm_serial_logstart(configFilePath, "./qxdmlog"
                                        /*"/mnt/sdcard/DiagGrabPro/conf/full configuration/diag_start.dat",
                                          "/mnt/sdcard/DiagGrabPro/log"*/
                                        ) >= 0)
                {
                        if(runmode == 2)
                        {
                                qualcomm_serial_log_teststart();
                        }
                }
        }
        else if(runmode == 1)
        {
                log_message("stop qualcomm serial log");
                return qualcomm_serial_logstop();
        }
        else
        {
                return g_is_qxdm_logging;
        }

        while(g_is_qxdm_logging)
        {
                sleep(30);
        }

error_exit:

        return 0;
}

